<?php 


/*******************************************************************************

* 简介：

* 1、模板语言使用PHP语言，而其它模板类使用自定义的专用语言，需要进行正则替换。

* 2、支持缓存机制，模板数据变化，就刷新缓存文件。

* 3、可以设定缓存时间，缓存过期，就刷新缓存文件。

* 4、支持配置文件方式初始化设定目录，也可以后期更改目录，更加灵活（也许是多余）。
* 
* $t = new View();



$t->templateDir  = './template';

$t->cacheDir     = './cache';

$t->serializeDir = './serialize';



$t->assign('title', $title);

$t->assign('hello', $hello);



$t->display("example.html");

********************************************************************************/

/**

* PHP视图模板类

* @class    PhpView

* @author   xie sheng tao <xie.s.t@163.com>

*/

class View

{

	/**

	* 是否使用缓存机制进行工作

	* @var  boolean  $cacheEnable   true-启用缓存机制；false-关闭缓存机制

	*/

	public $cacheEnable = true;



	/**

	* 缓存时间

	* 超过缓存时间则自动更新缓存。

	* @var  integer     $cacheExpire  0-永远不过期；> 0 判断。< 0 ？？ 或者 = 0 始终过期；> 0 判断；< 0 永远不过期

	*/

	public $cacheExpire = 0;



	/**

	* 模板文件的存贮目录

	* @var  string  $templateDir

	*/

	public $templateDir = '';



	/**

	* 缓存文件的存贮目录

	* @var string   $cacheDir

	*/

	public $cacheDir = '';



	/**

	* 序列化文件的存贮目录

	* @var  string  $serializeDir

	*/

	public $serializeDir = '';



	/**

	* 保存模板文件中使用的变量的名、值列表

	* @var  array   $m_templateVarList

	*/

	private $m_templateVarList = array();



	/**

	* 记住系统目录是否已经检查过并且符合要求。避免以全局方式使用时重复检查。

	* @var  boolean     $m_sysDirReady

	*/

	private $m_sysDirReady = false;



	/**

	* 当前操作使用的模板文件

	* @var  string  $m_templateFile

	*/

	private $m_templateFile = '';



	/**

	* 类的构造函数

	*/

	public function __construct()

	{

		$this->readConfig();

	}



	/**

	* 读取PhpView类的配置信息

	*/

	public function readConfig()

	{

		if(file_exists("config/view_config.php"))

		{

			include_once("config/view_config.php");

		} 

		if(isset($g_cacheEnable))

		{

			$this->cacheEnable = $g_cacheEnable;

		}

		if(isset($g_templateDir))

		{

			$this->templateDir =$g_templateDir;

		}

		if(isset($g_cacheDir))

		{

			$this->cacheDir = $g_cacheDir;

		}

		if(isset($g_serializeDir))

		{

			$this->serializeDir = $g_serializeDir;

		}

		if(isset($g_sysDirReady))

		{

			$this->m_sysDirReady = $g_sysDirReady;

		}

	}



	/**

	* 检测所需目录是否存在。如果不存在，则报错并退出。

	* 所需目录为：模板文件目录、缓存文件目录、序列化文件目录

	*/

	public function checkSysDir()

	{

		if($this->templateDir == '')

		{

			die("模板文件目录未设置。");

		}



		if(!is_readable($this->templateDir))

		{

			die("模板文件目录不可读。");

		}



		if($this->cacheDir == '')

		{

			die("缓存文件目录未设置。");

		}



		if(!(is_readable($this->cacheDir) && is_writable($this->cacheDir)))

		{

			die("缓存文件目录不可读写。");

		}



		if($this->serializeDir == '')

		{

			die("序列化文件目录未设置。");

		}



		if(!(is_readable($this->serializeDir) && is_writable($this->serializeDir)))

		{

			die("序列化文件目录不可读写。");

		}



		$this->m_sysDirReady = true;

		return;

	}



	/**

	* 指派模板文件中使用的变量

	* @param   string  $varName   在模板中使用的变量名

	* @param   any     &$varValue  PHP中支持的数据类型

	* or

	* @param   array   $varName    使用数组来传递名值列表，即变量名作为关联索引，变量值为元素值。

	*/

	public function assign($varName, $varValue = null)

	{

		if(func_num_args() == 1)

		{

			$varList = func_get_arg(0);

			if(gettype($varList) == 'array')

			{

				foreach($varList as $name=>$value)

				{

					$this->m_templateVarList[$name] = $value;

				}

			}

		}

		else if(gettype($varName) == 'string')

		{

			$this->m_templateVarList[$varName] = $varValue;

		}

		return;

	}



	/**

	* 调用模板文件，生成模板中的变量，输出到浏览器

	* @param   string  $file  模板文件名

	*/

	public function display($file)

	{

		if(!$this->m_sysDirReady)

		{

			$this->checkSysDir();

		}



		$this->m_templateFile = $file;



		if($this->cacheEnable)

		{

			$this->cacheOutput();

		}

		else

		{

			$this->directOutput();

		}

		return;

	}



	/**

	* 使用缓存机制处理模板

	* 实现原理：

	* 1、取得客户端请求的链接url。缓存文件和序列化文件的文件名使用此url命名。

	* 2、将存贮当前模板变量的数组序列化为一个字符串。

	* 3、读取模板文件对应的序列化文件，得到前一个模板变量数组的序列化字符串。

	* 4、判断前后两次序列化字符串是否相等。如果相等，则直接把缓存文件的内容输出到浏览器。

	*    否则，重新生成序列化文件和缓存文件，然后把模板处理结果输出到浏览器。

	*/

	private function cacheOutput()

	{

		$html = '';

		$cache_filename = @urlencode(basename($_SERVER['REQUEST_URI']));

		$cur_serialize = @serialize($this->m_templateVarList);

		$pre_serialize = $this->readSerialize($cache_filename);



		if($cur_serialize === $pre_serialize)

		{

			if(!$this->isCacheFileTimeout($cache_filename)){

				if($html = $this->readCacheFile($cache_filename))

				{

					echo '使用缓存文件.';

					echo $html;

					return;

				}

			}

			echo '缓存文件过期.';

		}



		echo '刷新缓存文件.';

		$this->saveSerialize($cache_filename, $cur_serialize);

		/*foreach($this->m_templateVarList as $name => $value)

		{

		eval("/$name = /$value;"); // 通过 eval 函数生成模板文件中使用的变量

		}*/

		extract($this->m_templateVarList);



		ob_start();

		@include($this->templateDir . '/' . $this->m_templateFile);

		//sleep(5);

		$html = ob_get_contents();

		ob_clean();

		$this->writeCacheFile($cache_filename, $html);

		echo $html;

		return;

	}



	/**

	* 直接将模板处理结果输出到浏览器，不使用缓存机制

	*/

	private function directOutput()

	{

		foreach($this->m_templateVarList as $name => $value)

		{

			eval("/$name = /$value;"); // 通过 eval 函数生成模板文件中使用的变量

		}

		ob_start();

		@include($this->templateDir . '/' . $this->m_templateFile);

		ob_flush();

		return;

	}
	
	public function toString(){
		
		foreach($this->m_templateVarList as $name => $value)
		
		{
					
			eval("$$name = \$value;"); // 通过 eval 函数生成模板文件中使用的变量
		
		}
		
		ob_start();		
		@include($this->templateDir . '/' . $this->m_templateFile);		
		$str = ob_get_contents ();		
		ob_end_clean();
		return $str;
	}



	/**

	* 将模板处理结果写入缓存文件

	* @param    string  $file       缓存文件路径

	* @param    string  $content    缓存内容

	* @return   null

	*/

	private function writeCacheFile($file, $content)

	{

		$filename = $this->cacheDir . '/' . $file;

		@file_put_contents($filename, $content);

		return;

	}



	/**

	* 读取缓存文件

	* @param    string  $file   缓存文件路径

	* @return   string          缓存文件的内容

	*/

	private function readCacheFile($file)

	{

		$filename = $this->cacheDir . '/' . $file;

		$html = @file_get_contents($filename);

		return $html;

	}



	/**

	* 保存序列化字符串到文本文件中

	* @param    string  $file       序列化文件路径

	* @param    string  $content    序列化数据的字符串

	* @return   null

	*/

	private function saveSerialize($file, $content)

	{

		$filename = $this->serializeDir . '/' . $file;

		@file_put_contents($filename, $content);

		return;

	}



	/**

	* 读取文本文件中存贮的序列化字符串

	* @param    string  $file       序列化文件路径

	* @return   string              序列化数据的字符串

	*/

	private function readSerialize($file)

	{

		$filename = $this->serializeDir . '/' . $file;

		$content = @file_get_contents($filename);

		return $content;

	}



	/**

	* 判断缓存文件是否过期

	* @param    string      $file   缓存文件

	* @return   boolean

	*/

	private function isCacheFileTimeout($file)

	{

		if($this->cacheExpire == 0)//缓存时间为0，表示永远不过期

		{

			return false;

		}



		$cacheFile = $this->cacheDir . '/' . $file;

		if(file_exists($cacheFile))

		{

			$modifyTime = filemtime($cacheFile);

			$currentTime = time();

			if(($currentTime - $modifyTime) > $this->cacheExpire){

				return true;

			}

			return false;

		}

		return true;

	}
	/**
	 * @return the $cacheEnable
	 */
	public function getCacheEnable() {
		return $this->cacheEnable;
	}

	/**
	 * @return the $cacheExpire
	 */
	public function getCacheExpire() {
		return $this->cacheExpire;
	}

	/**
	 * @return the $templateDir
	 */
	public function getTemplateDir() {
		return $this->templateDir;
	}

	/**
	 * @return the $cacheDir
	 */
	public function getCacheDir() {
		return $this->cacheDir;
	}

	/**
	 * @return the $serializeDir
	 */
	public function getSerializeDir() {
		return $this->serializeDir;
	}

	/**
	 * @return the $m_templateVarList
	 */
	public function getM_templateVarList() {
		return $this->m_templateVarList;
	}

	/**
	 * @return the $m_sysDirReady
	 */
	public function getM_sysDirReady() {
		return $this->m_sysDirReady;
	}

	/**
	 * @return the $m_templateFile
	 */
	public function getM_templateFile() {
		return $this->m_templateFile;
	}

	/**
	 * @param boolean $cacheEnable
	 */
	public function setCacheEnable($cacheEnable) {
		$this->cacheEnable = $cacheEnable;
	}

	/**
	 * @param number $cacheExpire
	 */
	public function setCacheExpire($cacheExpire) {
		$this->cacheExpire = $cacheExpire;
	}

	/**
	 * @param string $templateDir
	 */
	public function setTemplateDir($templateDir) {
		$this->templateDir = $templateDir;
	}

	/**
	 * @param string $cacheDir
	 */
	public function setCacheDir($cacheDir) {
		$this->cacheDir = $cacheDir;
	}

	/**
	 * @param string $serializeDir
	 */
	public function setSerializeDir($serializeDir) {
		$this->serializeDir = $serializeDir;
	}

	/**
	 * @param multitype: $m_templateVarList
	 */
	public function setM_templateVarList($m_templateVarList) {
		$this->m_templateVarList = $m_templateVarList;
	}

	/**
	 * @param boolean $m_sysDirReady
	 */
	public function setM_sysDirReady($m_sysDirReady) {
		$this->m_sysDirReady = $m_sysDirReady;
	}

	/**
	 * @param string $m_templateFile
	 */
	public function setM_templateFile($m_templateFile) {
		$this->m_templateFile = $m_templateFile;
	}




} // end class
